﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProgNetComponents.Utils;
using System.Data;
using ProgNetComponents.Design.Attributes;
using System.ComponentModel;
using ProgNetComponents.Validation.Design;
using System.Drawing.Design;

namespace ProgNetComponents.Validation.Rules
{
    /// <summary>
    /// Validation rule for ranges
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class RangeValidationRule<T> : ValidationRule, IDataValidationRule where T : IComparable
    {
        #region Static
        /// <summary>
        /// Initializes the <see cref="RangeValidationRule{T}"/> class.
        /// </summary>
        static RangeValidationRule()
        {
            GlobalDefaultErrorString = "Zakres jest niepoprawny.";
        }
        /// <summary>
        /// Gets or sets the global default error string.
        /// </summary>
        /// <value>
        /// The global default error string.
        /// </value>
        public static string GlobalDefaultErrorString { get; set; }
        #endregion

        #region Members
        /// <summary>
        /// The error string
        /// </summary>
        protected string _ErrorString;
        #endregion

        /// <summary>
        /// Gets or sets from column.
        /// </summary>
        /// <value>
        /// From column.
        /// </value>
        [Editor(typeof(IDataValidationRuleColumnNameEditor), typeof(UITypeEditor))]
        public string FromColumn { get; set; }

        /// <summary>
        /// Gets or sets to column.
        /// </summary>
        /// <value>
        /// To column.
        /// </value>
        [Editor(typeof(IDataValidationRuleColumnNameEditor), typeof(UITypeEditor))]
        public string ToColumn { get; set; }

        /// <summary>
        /// Specifies how nulls will be compared
        /// <para> True - null is equal to everything</para>
        /// <para> Fals - null is not equal to anything</para>
        /// <para> Default - null is equal to 0</para>
        /// </summary>
        /// <value>
        /// The nulls are equal.
        /// </value>
        public DefaultBool NullsAreEqual
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets Error to be set if validation fails
        /// </summary>
        /// <value>
        /// The error string.
        /// </value>
        [SerializationVisibilityByMethodAttribute("SerializeErrorString")]
        public string ErrorString
        {
            get
            {
                if (_ErrorString.IsNull())
                    return DefaultErrorString;
                return _ErrorString;
            }
            set { _ErrorString = value; }
        }

        /// <summary>
        /// Gets or sets if validation should stop on first error
        /// </summary>
        /// <value>
        ///   <c>true</c> if [stop on first error]; otherwise, <c>false</c>.
        /// </value>
        public bool StopOnFirstError
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the default error string.
        /// </summary>
        /// <value>
        /// The default error string.
        /// </value>
        protected virtual string DefaultErrorString
        {
            get
            {
                return GlobalDefaultErrorString;
            }
        }

        /// <summary>
        /// Gets formatted error string
        /// </summary>
        /// <value>
        /// The formated error string.
        /// </value>
        public virtual string FormatedErrorString
        {
            get { return ErrorString; }
        }

        /// <summary>
        /// Serializes the error string.
        /// </summary>
        /// <returns></returns>
        protected virtual DesignerSerializationVisibility SerializeErrorString()
        {
            if (_ErrorString.IsNotNull())
                return DesignerSerializationVisibility.Visible;
            return DesignerSerializationVisibility.Hidden;
        }

        /// <summary>
        /// Does the validate.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        protected override bool DoValidate(DataRow row)
        {
            bool result = true;
                bool invalid = false;
                if (NullsAreEqual != DefaultBool.Default &&
                    (row[FromColumn].IsNull() || row[ToColumn].IsNull()))
                {
                    switch (NullsAreEqual)
                    {
                        case DefaultBool.True:
                            invalid = true;
                            break;
                        case DefaultBool.False:
                            invalid = false;
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    T from = ConvertValue(row[FromColumn]);
                    T to = ConvertValue(row[ToColumn]);
                    invalid = from.CompareTo(to) >= 0;
                }

                if (invalid)
                {
                    result = false;
                    row.SetColumnError(FromColumn, FormatedErrorString);
                    row.SetColumnError(ToColumn, FormatedErrorString);
                    if (StopOnFirstError)
                        return result;
                }
            return result;
        }

        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected abstract T ConvertValue(object value);

        /// <summary>
        /// Called when [validation failed].
        /// </summary>
        /// <param name="row">The row.</param>
        protected override void OnValidationFailed(DataRow row)
        {

        }

        /// <summary>
        /// Gets or sets the data source.
        /// </summary>
        /// <value>
        /// The data source.
        /// </value>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        System.Data.DataTable IDataValidationRule.DataSource
        {
            get;
            set;
        }

    }

    /// <summary>
    /// 
    /// </summary>
    public class IntRangeValidationRule : RangeValidationRule<int>
    {
        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override int ConvertValue(object value)
        {
            return value.AsInt();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class DecimalRangeValidationRule : RangeValidationRule<decimal>
    {
        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override decimal ConvertValue(object value)
        {
            return value.AsDecimal();
        }
    }
}
